package com.personal.system.service.impl.content;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;
import com.personal.common.result.Result;
import com.personal.model.system.SysUser;
import com.personal.system.config.SecurityUtil;
import com.personal.system.entity.content.Article;
import com.personal.system.entity.content.Category;
import com.personal.system.entity.content.Tags;
import com.personal.system.entity.vo.ArticleDTO;
import com.personal.system.entity.vo.SystemArticleListVO;
import com.personal.system.exception.GlobalException;
import com.personal.system.mapper.content.ArticleMapper;
import com.personal.system.mapper.content.CategoryMapper;
import com.personal.system.mapper.content.TagsMapper;
import com.personal.system.mapper.sys.SysUserMapper;
import com.personal.system.service.content.ArticleService;
import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter;
import com.vladsch.flexmark.util.data.MutableDataSet;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;


/**
 * <p>
 * 博客文章表 服务实现类
 * </p>
 *
 * @author blue
 * @since 2021-08-18
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {

    private final CategoryMapper categoryMapper;
    private final SysUserMapper userMapper;
//
//    private final SystemConfigService systemConfigService;

    private final TagsMapper tagsMapper;

    private final SecurityUtil securityUtil;

//    private final SearchStrategyContext searchStrategyContext;

    private final RestTemplate restTemplate;

//    private final ElasticsearchUtil elasticsearchUtil;

    @Value("${baidu.url}")
    private String baiduUrl;


    /**
     *  后台获取所有文章
     * @return
     */
    @Override
    public Result selectArticleList(Map<String,Object> map) {
        Page<SystemArticleListVO> data = baseMapper.selectArticle(new Page<>((Integer)map.get("pageNo"), (Integer)map.get("pageSize")),map);
        data.getRecords().forEach(item ->{
            SysUser userInfo = userMapper.selectById(item.getUserId());
            item.setNickname(userInfo.getName());
        });
        return Result.ok(data);
    }

    /**
     *  后台获取文章详情
     * @return
     */
    @Override
    public Result selectArticleById(Long id) {
        ArticleDTO articleDTO = baseMapper.selectArticlePrimaryKey(id);
        articleDTO.setTags(tagsMapper.selectByArticleId(id));
        return Result.ok(articleDTO);
    }

    /**
     *  添加文章
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result  insertArticle(ArticleDTO article) {
        Article blogArticle = BeanUtil.copyProperties(article, Article.class);
        blogArticle.setUserId(securityUtil.getUserId().toString());
        //添加分类
        Long categoryId = savaCategory(article.getCategoryName());
        //添加标签
        List<Long> tagList = getTagsList(article);

        blogArticle.setCategoryId(categoryId);

        int insert = baseMapper.insert(blogArticle);
        if (insert > 0) {
            tagsMapper.saveArticleTags(blogArticle.getId(),tagList);
        }
        return Result.ok();
    }

    /**
     *  修改文章
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result updateArticle(ArticleDTO article) {
        Article blogArticle = baseMapper.selectById(article.getId());
        if (ObjectUtil.isNull(blogArticle)) {
            throw new GlobalException(404,"文章不存在!");
        }
        //只能修改属于当前登录用户的文章
        String loginId = securityUtil.getUserId().toString();
        if (!blogArticle.getUserId().equals(loginId) ){
            throw new GlobalException(404,"操作异常!");
        }

        //添加分类
        Long categoryId = savaCategory(article.getCategoryName());
        //添加标签
        List<Long> tagList = getTagsList(article);

        blogArticle = BeanUtil.copyProperties(article, Article.class);
        blogArticle.setCategoryId(categoryId);
        baseMapper.updateById(blogArticle);

        //先删出所有标签
        tagsMapper.deleteByArticleIds(Collections.singletonList(blogArticle.getId()));
        //然后新增标签
        tagsMapper.saveArticleTags(blogArticle.getId(),tagList);

        return Result.ok();
    }


    /**
     * 批量删除文章
     * @param ids
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result deleteBatchArticle(List<Long> ids) {
        int rows = baseMapper.deleteBatchIds(ids);
        tagsMapper.deleteByArticleIds(ids);
        return Result.ok(rows);
    }

    /**
     *  置顶文章
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result topArticle(ArticleDTO article) {
        baseMapper.putTopArticle(article);
        return Result.ok();
    }


    /**
     *  文章百度推送
     * @return
     */
    @Override
    public Result seoBatch(List<Long> ids) {

        HttpHeaders headers = new HttpHeaders();
        headers.add("Host", "data.zz.baidu.com");
        headers.add("User-Agent", "curl/7.12.1");
        headers.add("Content-Length", "83");
        headers.add("Content-Type", "text/plain");

        ids.forEach(item -> {
            String url = "http://www.shiyit.com/article/" + item;
            HttpEntity<String> entity = new HttpEntity<>(url, headers);
            restTemplate.postForObject(baiduUrl, entity, String.class);
        });
        return Result.ok();
    }

    /**
     *  抓取文章
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result reptile(String url) {
        try {
            String title = null;
            Elements tags = null;
            String content = null;
            Document document = Jsoup.connect(url).get();
            if (url.contains("csdn")){
                title  = document.getElementsByClass("title-article").get(0).text();
                tags  = document.getElementsByClass("tag-link");
                content  = document.getElementsByClass("article_content").get(0).toString();

            } else if (url.contains("juejin")){
                title  = document.title();
                tags = new Elements();
                tags.add(new Element("Spring Boot"));
                content  = document.getElementById("article-root").text();
            }
            if (StrUtil.isBlank(content)) {
                throw new GlobalException(404, "抓取文章失败!");
            }


            //爬取的是HTML内容，需要转成MD格式的内容
            String newContent = content.replaceAll("<code>", "<code class=\"lang-java\">");
            MutableDataSet options = new MutableDataSet();
            String markdown = FlexmarkHtmlConverter.builder(options).build().convert(newContent)
                    .replace("lang-java","java");

            //文章封面图片 由https://api.btstu.cn/该网站随机获取
            String strResult = restTemplate.getForObject(IMG_URL_API, String.class);
            JSONObject jsonObject = JSON.parseObject(strResult);
            Object imgUrl = jsonObject.get("imgurl");

            Article entity = Article.builder().userId(securityUtil.getUserIdWeb()).contentMd(markdown)
                    .categoryId(16l).isOriginal(0).originalUrl(url).summary(title)
                    .title(title).avatar(imgUrl.toString()).content(newContent).build();

            baseMapper.insert(entity);
            //为该文章添加标签
            List<Long> tagsId = new ArrayList<>();

            tags.forEach(item ->{
                String tag = item.text();
                Tags result = tagsMapper.selectOne(new QueryWrapper<Tags>().eq("name",tag ));
                if (result == null){
                    result = Tags.builder().name(tag).build();
                    tagsMapper.insert(result);
                }
                tagsId.add(result.getId());
            });
            tagsMapper.saveArticleTags(entity.getId(),tagsId);

            log.info("文章抓取成功，内容为:{}", JSON.toJSONString(entity));
        } catch (IOException e) {
            throw new GlobalException(404, e.toString());
        }
        return Result.ok();
    }

    /**
     *  发布或下架文章
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result psArticle(ArticleDTO article) {
        baseMapper.publishAndShelf(article);
        return Result.ok();
    }

    public static final String IMG_URL_API = "https://api.btstu.cn/sjbz/api.php?lx=fengjing&format=json";
    @Override
    public Result randomImg() {
        //文章封面图片 由https://api.btstu.cn/该网站随机获取
        String result = restTemplate.getForObject(IMG_URL_API, String.class);
        Object imgUrl = JSON.parseObject(result).get("imgurl");
        return Result.ok(imgUrl);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result pdfAnalysis(MultipartFile file) {
        String name = file.getOriginalFilename();
        String suffix = name.substring(file.getOriginalFilename().lastIndexOf(".")+1);
        if (!suffix.equals("pdf")) throw new GlobalException(404,"仅支持pdf文件!");
        String res = "";
        try {
            InputStream inputStream = file.getInputStream();
            PdfReader pdfReader = new PdfReader(inputStream);
            pdfReader.setAppendable(true);
            int numberOfPages = pdfReader.getNumberOfPages();
            for (int i = 1; i < numberOfPages + 1; i++) {
                String textFromPage = PdfTextExtractor.getTextFromPage(pdfReader, i);
                res += textFromPage;
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        Article article = new Article();
        article.setTitle(name);
        article.setSummary("面试相关的");
        article.setCategoryId(17l);
        article.setContent(res);
        String markdown = FlexmarkHtmlConverter.builder(new MutableDataSet()).build().convert(res);
        article.setContentMd(markdown);
        article.setUserId(securityUtil.getUserId().toString());
        this.baseMapper.insert(article);
        tagsMapper.saveArticleTags(article.getId(), Arrays.asList(63l));
        return Result.ok();
    }

    /**
     * 将数据库不存在的标签新增
     * @param article
     * @return
     */
    private List<Long> getTagsList(ArticleDTO article) {
        List<Long> tagList = new ArrayList<>();
        article.getTags().forEach(item ->{
            Tags tags = tagsMapper.selectOne(new QueryWrapper<Tags>().eq("name", item));
            if (tags == null){
                tags = Tags.builder().name(item).sort(0).build();
                tagsMapper.insert(tags);
            }
            tagList.add(tags.getId());
        });
        return tagList;
    }

    /**
     * 如果分类不存在则新增
     * @param categoryName
     * @return
     */
    private Long savaCategory(String categoryName) {
        Category category = categoryMapper.selectOne(new QueryWrapper<Category>().eq("name", categoryName));
        if (category == null){
            category = Category.builder().name(categoryName).sort(0).build();
            categoryMapper.insert(category);
        }
        return category.getId();
    }
}
